﻿
Imports std

Public MustInherit Class threadModel
    Public timeoutMS As Int64 = 24000

    Public Overridable Sub [stop]()
    End Sub

    Protected Function overtimelimit(ByVal startticks As Int64) As Boolean
        Return ticksToMilliseconds(Now.Ticks() - startticks) >= timeoutMS
    End Function

    Protected Function returnValue(ByVal this As ternary, ByVal rtn As ternary) As ternary
        If this = ternary.true Then
            If rtn = ternary.unknown Then
                Return this
            Else
                Return rtn
            End If
        Else
            If rtn = ternary.false Then
                Return rtn
            Else
                Return this
            End If
        End If
    End Function

    Private Function precheck(Of T)(ByVal d As T, Optional ByVal operationCount As Int64 = 1) As ternary
        If d Is Nothing Then
            Return ternary.false
        End If
        If operationCount < 0 Then
            Return ternary.false
        ElseIf operationCount = 0 Then
            Return ternary.true
        End If
        Return ternary.unknown
    End Function

    Private Function precheck(Of T, SELECTOR_T)(ByVal d As T, ByVal selectors As vector(Of SELECTOR_T)) As ternary
        If selectors Is Nothing Then
            Return precheck(d, 0)
        Else
            Return precheck(d, selectors.size())
        End If
    End Function

    'An abstract of Map - Reduce model
    Public Function multiOper(Of ROUND_RESULT_T, SELECTOR_T) _
                             (ByVal d As _do(Of SELECTOR_T, ROUND_RESULT_T, ternary),
                              ByVal final As _do(Of ROUND_RESULT_T, Boolean),
                              ByVal selectors As vector(Of SELECTOR_T)) As ternary
        If final Is Nothing Then
            final = Function(ByRef _NIU_ As ROUND_RESULT_T) As Boolean
                        Return True
                    End Function
        End If
        Dim final2 As _do(Of ROUND_RESULT_T, Boolean, Boolean) =
            Function(ByRef this As ROUND_RESULT_T, ByRef _NIU_ As Boolean) As Boolean
                Return do_(Function(ByRef i As ROUND_RESULT_T) As Boolean
                               Return final(i)
                           End Function, this, False)
            End Function
        Return multiOper(d, final2, selectors, Nothing)
    End Function

    Public Function multiOper(Of ROUND_RESULT_T, TOTAL_RESULT_T, SELECTOR_T) _
                             (ByVal d As _do(Of SELECTOR_T, ROUND_RESULT_T, ternary),
                              ByVal final As _do(Of ROUND_RESULT_T, TOTAL_RESULT_T, Boolean),
                              ByVal selectors As vector(Of SELECTOR_T),
                              ByRef total As TOTAL_RESULT_T) As ternary
        If final Is Nothing Then
            final = Function(ByRef _NIU_ As ROUND_RESULT_T, ByRef _NIU2_ As TOTAL_RESULT_T) As Boolean
                        Return True
                    End Function
        End If
        Dim final2 As _do(Of ternary, ROUND_RESULT_T, TOTAL_RESULT_T, Boolean) =
            Function(ByRef rst As ternary, ByRef this As ROUND_RESULT_T, ByRef t As TOTAL_RESULT_T) As Boolean
                If rst = ternary.true Then
                    Return do_(Function(ByRef i As ROUND_RESULT_T, ByRef j As TOTAL_RESULT_T) As Boolean
                                   Return final(i, j)
                               End Function, this, t, False)
                Else
                    Return True
                End If
            End Function

        Return multiOper(d, final2, selectors, total)
    End Function

    Public Function multiOper(Of ROUND_RESULT_T, SELECTOR_T) _
                             (ByVal d As _do(Of SELECTOR_T, ROUND_RESULT_T, ternary),
                              ByVal final As _do(Of ternary, ROUND_RESULT_T, Boolean),
                              ByVal selectors As vector(Of SELECTOR_T)) As ternary
        If final Is Nothing Then
            final = Function(ByRef _NIU_ As ternary, ByRef _NIU2_ As ROUND_RESULT_T) As Boolean
                        Return True
                    End Function
        End If
        Dim final2 As _do(Of ternary, ROUND_RESULT_T, Boolean, Boolean) =
            Function(ByRef rst As ternary, ByRef this As ROUND_RESULT_T, ByRef _NIU_ As Boolean) As Boolean
                Return do_(Function(ByRef r As ternary, ByRef t As ROUND_RESULT_T) As Boolean
                               Return final(r, t)
                           End Function, rst, this, False)
            End Function
        Return multiOper(d, final2, selectors)
    End Function

    <ThreadStatic()> Private Shared _finallock As sequentialLock = Nothing
    Private Shared Function finallock() As sequentialLock
        If _finallock Is Nothing Then
            _finallock = New sequentialLock()
        End If
        Return _finallock
    End Function

    Public Function multiOper(Of ROUND_RESULT_T, TOTAL_RESULT_T, SELECTOR_T) _
                             (ByVal d As _do(Of SELECTOR_T, ROUND_RESULT_T, ternary),
                              ByVal final As _do(Of ternary, ROUND_RESULT_T, TOTAL_RESULT_T, Boolean),
                              ByVal selectors As vector(Of SELECTOR_T),
                              Optional ByRef total As TOTAL_RESULT_T = Nothing) As ternary
        Dim rtn As ternary = precheck(d, selectors)
        If rtn = ternary.unknown Then
            Dim lock As sequentialLock = Nothing
            lock = finallock()
            Dim t As TOTAL_RESULT_T = total
            rtn = multiOper(Function(ByRef s As SELECTOR_T) As ternary
                                Return do_(Function(ByRef s1 As SELECTOR_T) As ternary
                                               Dim this As ROUND_RESULT_T = Nothing
                                               Dim r As ternary = Nothing
                                               r = d(s1, this)
                                               If Not final Is Nothing Then
                                                   lock.wait()
                                                   If Not final(r, this, t) Then
                                                       raiseError(errorHandle.errorType.exclamation,
                                                                  "cannot finish final ", invokeMethodName(final))
                                                   End If
                                                   lock.release()
                                               End If
                                               Return r
                                           End Function, s, ternary.false)
                            End Function, selectors)
            total = t
        End If

        Return rtn
    End Function

    Public Function multiOper(Of SELECTOR_T) _
                             (ByVal d As _do(Of SELECTOR_T, ternary),
                              ByVal selectors As vector(Of SELECTOR_T)) As ternary
        Dim rtn As ternary = precheck(d, selectors)
        If rtn = ternary.unknown Then
            Dim i As Int32 = -1
            Return operImpl(Function() As ternary
                                Return do_(Function() As ternary
                                               Dim cur As Int32 = 0
                                               cur = Threading.Interlocked.Increment(i)
                                               assert(cur >= 0 AndAlso cur < selectors.size())
                                               Return d(selectors(cur))
                                           End Function, ternary.false)
                            End Function,
                            selectors.size())
        Else
            Return rtn
        End If
    End Function

    Public Function singleOper(Of SELECTOR_T) _
                              (ByVal d As _do(Of SELECTOR_T, ternary), ByVal selector As SELECTOR_T) As ternary
        Const operationCount As Int64 = 1
        Dim rtn As ternary = precheck(d, operationCount)
        If rtn = ternary.unknown Then
            Return operImpl(Function() As ternary
                                Return do_(Function() As ternary
                                               Return d(selector)
                                           End Function, ternary.false)
                            End Function, operationCount)
        Else
            Return rtn
        End If
    End Function

    Public Function multiOper(ByVal d As _do(Of ternary),
                              ByVal operationCount As Int64) As ternary
        Dim rtn As ternary = precheck(d, operationCount)
        If rtn = ternary.unknown Then
            Return do_(Function() As ternary
                           Return operImpl(d, operationCount)
                       End Function, ternary.false)
        Else
            Return rtn
        End If
    End Function

    Public Function singleOper(ByVal d As _do(Of ternary)) As ternary
        Const operationCount As Int64 = 1
        Dim rtn As ternary = precheck(d, operationCount)
        If rtn = ternary.unknown Then
            Return operImpl(d, operationCount)
        Else
            Return rtn
        End If
    End Function

    Protected MustOverride Function operImpl(ByVal d As _do(Of ternary), ByVal operationCount As Int64) As ternary
End Class
